package com.mh.system.service.impl;

import com.mh.system.domain.SysArea;
import com.mh.system.domain.dto.SysAreaDTO;
import com.mh.system.mapper.SysAreaMapper;
import com.mh.system.service.SysAreaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

//实现区域树形结构
@Service
public class SysAreaServiceImpl implements SysAreaService {

    @Autowired
    private SysAreaMapper sam;

    @Override
    //方法1: 获取省级+市级
    public List<SysAreaDTO> findAreaDTO() {
        //从数据库中获取所有的区域数据，返回一个List<SysArea>
        List<SysArea> list = sam.findAll();

        return list.stream() //将List<SysArea>转换为一个流（Stream）,用于处理集合数据

                //.filter 接受一个 Predicate（即一个返回布尔值的函数）  作为参数，只有满足条件的元素才会被保留下来
                //过滤出所有parentCode为0的区域，这些区域是树的根节点
                .filter(area -> area.getParentCode().equals(0))

                .map(area -> { //将每个根节点区域转换为SysAreaDTO对象，并设置其子节点
                    SysAreaDTO areaDTO = new SysAreaDTO();

                    areaDTO.setCode(area.getCode()); //从SysArea实体类获取当前区域的code,并赋值
                    areaDTO.setName(area.getName()); //同上
                    //获取当前区域的下一级区域(获取方法getChildrenArea在下方定义,在此调用即可),并赋值
                    //传入参数: 根节点的对象areaDTO,实体类SysArea所有区域的集合
                    areaDTO.setChildren(getChildrenArea(areaDTO,list));

                    return areaDTO; //code,name,下一级区域赋值后的对象返回

                }).collect(Collectors.toList()); //将流转换回一个List<SysAreaDTO>
    }

    /** 方法2: 获取市级以下的所有级别-->自己调用自己一直会循环,直到没有下一级
     * 递归设置区域信息
     * @param areaDTO 上级区域信息(根节点)
     * @param list  所有区域信息
     */
    private List<SysAreaDTO> getChildrenArea(SysAreaDTO areaDTO, List<SysArea> list) {

        List<SysArea> subAreaList = list.stream()
                                        //获取当前父区域的子节点
                                        //区域结果集中, 所有区域的集合的父id = 根节点区域code --> 表示该区域id是根节点下面的子节点
                                        //把这些跟父id一致的区域code筛选出来
                                        .filter(area -> area.getParentCode().equals(areaDTO.getCode()))
                                        //把当前流转换为一个List集合
                                        .collect(Collectors.toList());

        //如果子节点的集合不为空,长度不为0-->表示有子节点
        if( ! CollectionUtils.isEmpty(subAreaList) ){

            return subAreaList.stream() //子节点集合转换为流
                                .map(area -> { //将每个子节点(跟节点的子节点)区域转换为SysAreaDTO对象，并设置其子节点的子节点
                                    SysAreaDTO subAreaDTO = new SysAreaDTO();

                                    subAreaDTO.setName(area.getName());
                                    subAreaDTO.setCode(area.getCode());
                                    //设置子节点,递归调用直到获取到叶子结点为止
                                    subAreaDTO.setChildren(getChildrenArea(subAreaDTO,list)); //递归调用: 自己调用自己

                                    return subAreaDTO;
                                }).collect(Collectors.toList());
        }
        return null; //子节点集合为空,返回null
    }
}
